package com.pgy.backend.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.pgy.backend.entity.EvaluateRecords;
import com.pgy.backend.entity.TeacherGradeInfo;
import com.pgy.backend.entity.TeacherTeam;
import com.pgy.backend.mapper.EvaluateRecordsMapper;
import com.pgy.backend.mapper.PointerMapper;
import com.pgy.backend.mapper.TeacherGradeInfoMapper;
import com.pgy.backend.service.TeacherGradeInfoService;
import com.pgy.backend.service.TeacherTeamService;
import com.pgy.backend.service.impl.EvaluateRecordsService;
import com.pgy.backend.utils.RedisCache;
import com.pgy.backend.utils.singleton;
import com.pgy.backend.vo.ResultData;
import com.pgy.backend.vo.ReturnCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;


@RestController
@RequestMapping("/records")
// @PreAuthorize("hasAnyAuthority('teacher','root','teacher')")
@Api(tags = "算分记录相关接口")
@SuppressWarnings("all")
public class EvaluateRecordsController {
    @Autowired
    EvaluateRecordsMapper evaluateRecordsMapper;
    @Autowired
    EvaluateRecordsService evaluateRecordsService;
    @Autowired
    PointerMapper pointerMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private TeacherGradeInfoMapper teacherGradeInfoMapper;
    @Autowired
    private TeacherGradeInfoService teacherGradeInfoService;
    @Autowired
    private TeacherTeamService teacherTeamService;

    @GetMapping("/all")
    @ApiImplicitParam(name = "id", value = "教师的ID值")
    @ApiOperation(value = "计算对应教师评分")
    public ResultData caculate() {

        List<Long> idList = evaluateRecordsMapper.selectIds();
        Iterator<Long> iterator = idList.iterator();

        //获取所有状态为0的指标
        List<EvaluateRecords> teach;
        while (iterator.hasNext()) {
            Long id = iterator.next();
            synchronized (singleton.INSTANCE) {//每次对单个老师算分时都需要上锁修改保证单个用户的数据一致性
                teach = evaluateRecordsMapper.findRecords(id);
                if (CollectionUtils.isEmpty(teach)) {
                    continue;
                } else {
                    // teach.forEach();
                    //设置为-1分数计算中
                    teach.forEach(e -> e.setStatus(-1));
                    evaluateRecordsService.updateBatchById(teach);
                }
            }

            //每个分数大概都存在2个或以上的父类、所以设置容量减少冲突和扩容
            Map<String, TeacherGradeInfo> map = new HashMap<>(teach.size() * 3);
            //检查数据库
            List<TeacherGradeInfo> nodes = teacherGradeInfoMapper.selectByIds(id);
            if (CollectionUtils.isNotEmpty(nodes)) {
                nodes.forEach(teacherGradeInfo -> map.put(teacherGradeInfo.getSuperPointerNumber(), teacherGradeInfo));
            }
            for (EvaluateRecords e : teach) {
                String pointerNumber = e.getPointerId();//获取evaluateRecords的pointerId

                //如果不存在上一级就跳过
                if (pointerNumber.length() == 2) {
                    continue;
                }
                //抽取父级指针
                String[] pointerNumbers = extracted(pointerNumber);

                for (String number : pointerNumbers) { //
                    TeacherGradeInfo t = map.get(number);
                    if (Objects.isNull(t)) {
                        t = new TeacherGradeInfo(e.getTeachId(), e.getGrade(), number.length() / 2, number);
                    } else {
                        //加上分数
                        t.setPointerGrade(t.getPointerGrade() + e.getGrade());
                    }
                    map.put(number, t);
                }
            }
            boolean success = teacherGradeInfoService.saveOrUpdateBatch(map.values());
            if (success) {
                //设置状态码为1、部分回档
                teach.forEach(e -> e.setStatus(1));
                evaluateRecordsService.updateBatchById(teach);
            } else {
                // 重置
                teach.forEach(e -> e.setStatus(0));
                evaluateRecordsService.updateBatchById(teach);
            }
        }
        return ResultData.success("分数更新成功", null);
    }

    /**
     * 抽取父级指针
     *
     * @param pointerNumber
     * @return
     */
    private String[] extracted(String pointerNumber) {
        String[] pointerNumbers = new String[pointerNumber.length() / 2 - 1];
        for (int i = 2, j = 0; i != pointerNumber.length(); i += 2) {
            pointerNumbers[j++] = pointerNumber.substring(0, i);
        }
        return pointerNumbers;
    }

    @GetMapping("/get/{id}")
    @ApiImplicitParam(name = "id", value = "教师的ID值")
    @ApiOperation(value = "获取对应教师得分记录")
    public ResultData getrecords(@PathVariable Long id) {
        List<EvaluateRecords> teachNode = evaluateRecordsService.list(new LambdaQueryWrapper<EvaluateRecords>()
                .ne(EvaluateRecords::getStatus, 2));
        List<TeacherTeam> divideTeachNode = teacherTeamService.list(new LambdaQueryWrapper<TeacherTeam>()
                .eq(TeacherTeam::getLeaderTeacherId, id));
        // Map<String,>
        List<TeacherGradeInfo> teachCalculate = teacherGradeInfoService.list(new LambdaQueryWrapper<TeacherGradeInfo>()
                .eq(TeacherGradeInfo::getTeachId, id));
        HashMap<String, Object> map = new HashMap<>();
        map.put("计算后节点", teachCalculate);
        map.put("非划分-分数节点", teachNode);
        map.put("划分-分数节点", divideTeachNode);
        return ResultData.success(ReturnCode.CODE_200.getMessage(), map);
    }

    @GetMapping("/get/all")
    @ApiImplicitParam(name = "id", value = "教师的ID值")
    @ApiOperation(value = "获取所有教师当前总分数")
    public ResultData getrecords() {

        List<EvaluateRecords> teachs = evaluateRecordsService.list();

        Map<Long, List<EvaluateRecords>> teachMap = teachs.stream().collect(Collectors.groupingBy(EvaluateRecords::getTeachId));

        Iterator<Map.Entry<Long, List<EvaluateRecords>>> iterator = teachMap.entrySet().iterator();
        HashMap<Long, Integer> gradeMap = new HashMap<>();
        while (iterator.hasNext()) {
            Map.Entry<Long, List<EvaluateRecords>> grades = iterator.next();
            List<EvaluateRecords> value = grades.getValue();
            AtomicReference<Integer> sum = new AtomicReference<>(0);
            value.forEach(e -> sum.updateAndGet(v -> v + e.getGrade()));
            gradeMap.put(grades.getKey(), sum.get());
        }
        // teach
        return ResultData.success(ReturnCode.CODE_200.getMessage(), teachMap);
    }

    @GetMapping("/divide")//分数划分
    @ApiImplicitParam(name = "id,teachId, teachId_andGrade", value = "队长id 、后面以多个 id_分数组成")
    @ApiOperation(value = "分数划分")
    public ResultData divideRecords(@RequestParam Long id,
                                    @RequestParam Long teachId,
                                    @RequestParam String... teachId_Grade) {
        // TODO 划分权限校验、需要保证id为团队队长、同时需要校验划分对象
        EvaluateRecords teach = evaluateRecordsMapper.selectById(id);
        TeacherTeam one = teacherTeamService.getOne(new LambdaQueryWrapper<TeacherTeam>()
                .eq(TeacherTeam::getLeaderTeacherId, teachId)
                .eq(TeacherTeam::getPointerNumber, teach.getPointerId()));
        if (teach.getStatus() == 2) {
            return ResultData.error(500, "已划拨");
        }
        String teachers = "";
        String grades = "";
        for (String string : teachId_Grade) {
            String[] split = string.split("_");
            teachers += split[0] + ",";
            grades += split[1] + ",";
        }
        teachers = teachers.substring(0, teachers.length() - 1);
        grades = grades.substring(0, grades.length() - 1);

        TeacherTeam teacherTeam = new TeacherTeam(teachId, teach.getPointerId(), teachers, grades, 0);
        teach.setStatus(2);
        evaluateRecordsService.updateById(teach);
        boolean save = teacherTeamService.save(teacherTeam);

        return save ? ResultData.success(ReturnCode.CODE_200.getMessage(), null) : ResultData.error(500, "划分失败");

    }
}
